home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 …SCII & the Runetime Code / ADC Developer CD (1992-07) (''Butch ASCII And The Runtime Code'')_iso / Dev.CD 199207.iso / Development Platforms / Apple II / HyperCardIIGS / Developer Documentation / ASCII Text / XCMD. XFCNs < prev   
Encoding:
Text File  |  1992-02-27  |  35.5 KB  |  835 lines  |  [TEXT/pdos]

  1.  
  2.  
  3. 1
  4.  
  5.  
  6. XCMD and XFCN: The Magic Hooks That Extend HyperTalk
  7.  
  8. This documentation by Andy Stadler and Darin Acquistapace
  9. For HyperCard IIGS 1.1
  10.  
  11. cApple Computer, Inc. 1987, 1989-1992
  12. All Rights Reserved.
  13.  
  14.  
  15. (Thanks to Ted Kaehler who wrote the original of this paper)
  16.  
  17.  
  18. XCMD's and XFCN's are a powerful method of extending the capabilities 
  19. of HyperCard IIGS.  Quite simply, an XCMD or XFCN is a code resource 
  20. containing any compiled code the user wishes.  XCMD's and XFCN's can be 
  21. used where HyperTalk might be too slow (eg complicated sorts), as 
  22. device or hardware controllers (eg LaserDisk controllers) or for 
  23. anything else the programmer desires.
  24.  
  25. A note on terminology.  For most purposes, XCMD's and XFCN's are 
  26. identical, so unless necessary to draw a distinction, this document 
  27. will use the term XCMD to describe both types of X-thing.
  28.  
  29. XCMD's are inserted into the normal search path, in locations similar 
  30. to standard HyperTalk handlers.  The resource forks of the current 
  31. stack, home stack and hypercard itself are searched and any XCMD 
  32. therein becomes part of the language.  Just as a handler may either 
  33. extend the language or actually replace features, so may an XCMD.  The 
  34. inheritance path is:
  35.  
  36. Button (or Field)
  37. Card
  38. Stack
  39. Any XCMD currently open because it owns an XWindow(s).
  40. Stack XCMD
  41. Home
  42. Home XCMD
  43. XCMD in HyperCard application file
  44. HyperCard command
  45.  
  46. An XCMD or XFCN is a code resource of types $801E and $801F 
  47. respectively.  In addition name resources (type $8014) must exist 
  48. because the language can only reference these resources by name.  You 
  49. can create an XCMD and it's name with RezIIGS,  and you can move them 
  50. from file to file with RMover, the ResCopy XCMD, or with any other 
  51. resource moving tool.
  52.  
  53. XCMD's are called using the standard Pascal/toolbox stack based method.  
  54. They are called in full native mode, with a single parameter pushed 
  55. onto the stack.  On exit, the XCMD must pop the parameter, and must 
  56. return with the same processor mode and direct page.  All other 
  57. registers may be trashed.  These rules are important for assembly 
  58. language programmers but high-level languages use glue to take care of 
  59. all the "dirty work."
  60.  
  61. Once inside the XCMD, the programmer has almost limitless capabilities.  
  62. The user may request memory, and make OS or ToolBox calls.  New 
  63. extensions in HyperCard IIGS version 1.1 allow XCMD's to own windows 
  64. and interact with the user through them.  The only practical limitation 
  65. of XCMD's is that the entire package including all code and data must 
  66. fit in a single OMF segment - giving an upper bound of 64k!
  67.  
  68. An XCMD can be expressed in Pascal with the following description:
  69.  
  70. PROCEDURE EntryPoint(paramBlock: XCmdPtr);
  71.  
  72. All information is interchanged with HyperCard IIGS through a structure 
  73. called an  XCmdBlock.  Note that this is the only parameter ever passed 
  74. to an XCMD.  If the HyperTalk script passes any parameters, they will 
  75. be installed into the parameter block itself.  The XCmdBlock appears as 
  76. follows:
  77.  
  78. XCmdPtr = ^XCmdBlock; 
  79. XCmdBlock = RECORD
  80.      paramCount:    INTEGER;
  81.      params:   ARRAY[1..16] OF Handle;
  82.      returnValue:   Handle;
  83.      passFlag: BOOLEAN;
  84.      userID:   INTEGER;
  85.      returnStat:    BOOLEAN;
  86.             END;
  87.  
  88. The fields are defined as follows:
  89.  
  90. paramCount is the number of arguments in the XCMD invocation.  This 
  91. does not include the XMCD name itself.  For example, the command Flash 
  92. 5 has a parmCount of 1.
  93.  
  94. params is an array of handles.  Each handle contains a zero-terminated 
  95. string containing a single parameter from the invocation.  For example, 
  96. the command Flash 5 will create a single handle in params[1] containing 
  97. '5' and a zero terminater.  The other 15 entries are undefined.
  98.  
  99. returnValue is used in three different ways.  For XCMD's,  a string 
  100. returned here will be placed into "the result".  For  XFCN's, the 
  101. function result is returned here, and "the result" is never affected.  
  102. Finally, for either type, if returnStat is TRUE, the string here will 
  103. be displayed as a script error (see returnStat below).
  104.  
  105. In either case, the result is returned by creating a new handle and 
  106. putting the result in it (zero terminated string).  HyperCard IIGS will 
  107. dispose the handle.  The field is initialized to NIL before calling the 
  108. XCMD, so if you wish to return the empty string, just leave the field 
  109. alone.
  110.  
  111. passFlag is a flag telling HyperCard IIGS how to complete the message.  
  112. If it returns FALSE (its unmodified state) the XCMD has handled the 
  113. message.  If the code sets passFlag to TRUE, the message will continue 
  114. to pass through the message heirarchy.  Setting passFlag to true is 
  115. exactly equivalent to invoking the command pass messageName in a 
  116. HyperTalk handler.
  117.  
  118. userID is a IIGS user ID.  A unique ID will be assigned to each 
  119. concurrent invocation of each different XCMD.  That is, no two running 
  120. XCMDs will ever be given the same ID at the same time, even if they 
  121. recurse into each other.  The XCMD should use this ID for all memory 
  122. requests.  Please clean up all your handles before exiting!
  123.  
  124. returnStat allows XCMDs to report an error using the script error 
  125. reporting mechanism.  If returnStat is TRUE, the returnValue will be 
  126. displayed in a script error dialog box, along with "script" or "cancel" 
  127. buttons.  This allows XCMD to cleanly report errors in parameters or 
  128. usage.
  129.  
  130.  
  131. MACHINE STATE ON XCMD LAUNCH
  132.  
  133. When you launch an XCMD, the following machine state may be depended 
  134. on:
  135.  
  136.   Full native 16 bit mode.
  137.   The current grafport is the card window.
  138.   Resource search path is set to infinite search from the current stack 
  139. file on down.
  140.  
  141.  
  142. MAKING CALLBACKS
  143.  
  144. At any time, an XCMD may call back into HyperCard IIGS.  From a high-
  145. level language the call descriptions below should be enough.  For 
  146. assembly, the following notes should help:
  147.  
  148. o     The callback routines are accessed similar to pascal or toolbox 
  149. procedures:  push a result space if function, push parameters.  The X 
  150. register is loaded with the call #, and the "HyperCard IIGS Vector" is 
  151. then called as a subroutine:  JSL $E10220.  Callbacks follow mostly the 
  152. same rules as Tool Calls:  -- All params and results are passed on the 
  153. stack -- The A,X,Y registers are undefined (note: no error codes or C 
  154. flag) -- Databank and Direct Page -will- be preserved.
  155. o     HyperCard IIGS assumes that XCMDs will place their global data 
  156. adjacent to the XCMD code.  Therefore, to aid the XCMD, the data bank 
  157. will be set to the same bank as the XCMD's code before it is called.  
  158. If the XCMD wishes to place globals elsewhere, it is free to modify the 
  159. data bank register, as HyperCard IIGS will restore the bank register 
  160. correctly when the XCMD completes.
  161. o    The technique for returning strings as function results is as 
  162. follows:  (1)  Push a pointer to a string-sized result space.  (2)  
  163. Push params.  (3)  Load X with function number.  (4)  Call entry point.  
  164. Callback will pop params, but leaves the result pointer, so (5)  pop 
  165. the result pointer.  This is the method used by the MPW PascalIIGS 
  166. compiler.
  167.  
  168. In addition, notice that several of the calls create and return a new 
  169. handle;  this handle is not created with the XCMD's user ID.  Do not 
  170. ever DisposeAll(parms^.userID), for three reasons:  1.  If you have 
  171. created data and passed it back through a callback, HyperCard IIGS 
  172. might still be using it;   2.  The user ID's may be re-used, and some 
  173. XCMD's keep data around from one invocation to the next.   If you 
  174. DisposeAll with your current userID, you might destroy data held by an 
  175. earlier XCMD.  3.  The user ID is preserved when calling an XCMD that 
  176. owns XWindows in response to window events, a single XCMD may own 
  177. multiple windows and executing a DisposeAll will release memory that 
  178. may still be required in conjunction with other windows.
  179.  
  180. The following callbacks have been defined:
  181.  
  182. PROCEDURE SendCardMessage(msg: Str255); Asm #1
  183.  
  184. Send a HyperCard message (a command with arguments) to the current 
  185. card.
  186.  
  187.  
  188.  
  189. FUNCTION EvalExpr(expr: Str255): Handle;     Asm #2
  190.  
  191. Evaluate a HyperCard expression and return the answer.  The answer is a 
  192. handle to a zero-terminated string.
  193.  
  194. FUNCTION StringLength(strPtr: Ptr): LongInt; Asm #3
  195.  
  196. Count the characters from where strPtr points until the next zero byte. 
  197. Does not count the zero itself. strPtr must be a zero-terminated 
  198. string.
  199.  
  200. FUNCTION StringMatch(pattern: Str255; target: Ptr): Ptr;    Asm #4
  201.  
  202. Perform case-insensitive match looking for pattern anywhere in  target, 
  203. returning a pointer to first character of the first match,  in  target 
  204. or NIL if no match found. pattern is a Pascal string,  and target is a 
  205. zero-terminated string.
  206.  
  207. PROCEDURE SendHCMessage(msg: Str255);   Asm #5
  208.  
  209. Send a HyperCard message (a command with arguments) to HyperCard.
  210.  
  211. PROCEDURE ZeroBytes(dstPtr: Ptr; longCount: LongInt);  Asm #6
  212.  
  213. Write zeros into memory starting at dstPtr and going for longCount 
  214. number of bytes.
  215.  
  216. FUNCTION PasToZero(str: Str255): Handle;     Asm #7
  217.  
  218. Convert a Pascal string to a zero-terminated string. Returns a handle 
  219. to a new  zero-terminated string. The caller must dispose the handle.
  220.  
  221. PROCEDURE ZeroToPas(zeroStr: Ptr; VAR pasStr: Str255); Asm #8
  222.  
  223. Fill the Pascal string with the contents of the zero-terminated string. 
  224. You create the Pascal string and pass it in as a VAR parameter. Useful 
  225. for converting the arguments of any XCMD to Pascal strings.
  226.  
  227. FUNCTION StrToLong(str: Str31): LongInt;     Asm #9
  228.  
  229. Convert a string of ASCII decimal digits to an unsigned long integer.
  230.  
  231. FUNCTION StrToNum(str: Str31): LongInt; Asm #10
  232.  
  233. Convert a string of ASCII decimal digits to a signed long integer.  
  234. Negative sign is allowed.
  235.  
  236. FUNCTION StrToBool(str: Str31): BOOLEAN;     Asm #11
  237.  
  238. Convert the Pascal strings 'true' and 'false' to booleans.
  239.  
  240. FUNCTION StrToExt(str: Str31): Extended;     Asm #12
  241.  
  242. Convert a string of ASCII decimal digits to an extended floating point 
  243. value.
  244.  
  245.  
  246.  
  247.  
  248. FUNCTION LongToStr(posNum: LongInt): Str31;  Asm #13
  249.  
  250. Convert an unsigned long integer to a Pascal string.
  251.  
  252. FUNCTION NumToStr(num: LongInt): Str31; Asm #14
  253.  
  254. Convert a signed long integer to a Pascal string.
  255.  
  256. FUNCTION NumToHex(num: LongInt; nDigits: INTEGER): Str31; Asm #15
  257.  
  258. Convert an unsigned long integer to a hexadecimal number and put it 
  259. into a Pascal string.
  260.  
  261. FUNCTION BoolToStr(bool: BOOLEAN): Str31;    Asm #16
  262.  
  263. Convert a BOOLEAN to 'true' or 'false'.
  264.  
  265. FUNCTION ExtToStr(num: Extended): Str31;     Asm #17
  266.  
  267. Convert an extended long integer to decimal digits in a string.
  268.  
  269. FUNCTION GetGlobal(globName: Str255): Handle;     Asm #18
  270.  
  271. Return a new handle to a zero-terminated string containing the value of 
  272. the specified HyperTalk global variable.  The caller must dispose this 
  273. handle.
  274.  
  275. PROCEDURE SetGlobal(globName: Str255; globValue: Handle); Asm #19
  276.  
  277. Set the value of the specified HyperTalk global variable to be the 
  278. zero-terminated string in globValue. The contents of the Handle are 
  279. copied, so you must still dispose it afterwards.
  280.  
  281. FUNCTION GetFieldByName(cardFieldFlag: BOOLEAN; fieldName: 
  282. Str255): Handle;    Asm #20
  283.  
  284. Return a handle to a zero-terminated string containing the value of 
  285. field fieldName on the current card. You must dispose the handle.  
  286. cardFieldFlag set to false indicates background, instead of card, 
  287. field.
  288.  
  289. FUNCTION GetFieldByNum(cardFieldFlag: BOOLEAN; fieldNum: 
  290. INTEGER): Handle;   Asm #21
  291.  
  292. Return a handle to a zero-terminated string containing the value of 
  293. field fieldNum on the current card. You must dispose the handle.
  294.  
  295. FUNCTION GetFieldByID(cardFieldFlag: BOOLEAN; fieldID: INTEGER): 
  296. Handle;   Asm #22
  297.  
  298. Return a handle to a zero-terminated string containing the value of the 
  299. field while ID is fieldID. You must dispose the handle.
  300. PROCEDURE SetFieldByName(cardFieldFlag: BOOLEAN; fieldName: 
  301. Str255; fieldVal: Handle);    Asm #23
  302.  
  303. Set the value of field fieldName to be the zero-terminated string in 
  304. fieldVal. The contents of the Handle are copied, so you must still 
  305. dispose it afterwards.
  306.  
  307. PROCEDURE SetFieldByNum(cardFieldFlag: BOOLEAN; fieldNum: 
  308. INTEGER; fieldVal: Handle);   Asm #24
  309.  
  310. Set the value of field fieldNum to be the zero-terminated string in 
  311. fieldVal. The contents of the Handle are copied, so you must still 
  312. dispose it afterwards.
  313.  
  314. PROCEDURE SetFieldByID(cardFieldFlag:BOOLEAN; fieldID: INTEGER; 
  315. fieldVal: Handle);  Asm #25
  316.  
  317. Set the value of the field whose ID is fieldID to be the zero-
  318. terminated string in fieldVal. The contents of the Handle are copied, 
  319. so you must still dispose it afterwards.
  320.  
  321. FUNCTION StringEqual(str1,str2: Str255): BOOLEAN; Asm #26
  322.  
  323. Return true if the two strings have the same characters. Case 
  324. insensitive compare of the strings.
  325.  
  326. PROCEDURE ReturnToPas(zeroStr: Ptr; VAR pasStr: Str255); Asm #27
  327.  
  328. zeroStr points into a zero-terminated string. Collect the characters 
  329. from there to the next carriage Return or the end of the string, and 
  330. return them in the Pascal string pasStr.
  331.  
  332. PROCEDURE ScanToReturn(VAR scanPtr: Ptr);    Asm #28
  333.  
  334. Move the pointer scanPtr along a zero-terminated string until it points 
  335. at a Return character or a zero byte.
  336.  
  337. PROCEDURE ScanToZero(VAR scanPtr: Ptr); Asm #29
  338.  
  339. Move the pointer scanPtr along a zero-terminated string until it points 
  340. at a zero byte.
  341.  
  342. FUNCTION GSToPString(src: GSString255Hndl): Str255;    Asm #30
  343.  
  344. Convert a GS/OS Class 1 input string (length word + text) into a pascal 
  345. string.  If the source string has more than 255 characters, only the 
  346. first 255 will be copied.
  347.  
  348. FUNCTION PToGSString(src: Str255): GSString255Hndl;    Asm #31
  349.  
  350. Convert a Pascal string to a GS/OS Class 1 input string (length word + 
  351. text).  If the source string is empty, NIL is returned; otherwise a new 
  352. handle is created and filled with the text.
  353.  
  354. FUNCTION CopyGSString(src: GSString255Hndl): GSString255Hndl;
  355.      Asm #32
  356. Simply copies a GS/OS Class 1 input string (length word + text).  If 
  357. the handle is NIL or empty or contains a length word of zero, NIL is 
  358. returned, otherwise a new handle is created with an exact duplicate of 
  359. the input text.
  360.  
  361. FUNCTION GSConcat(src1, src2: GSString255Hndl): GSString255Hndl;
  362.      Asm #33
  363. Concatenates two GS/OS Class 1 input strings (length word + text).  If 
  364. both inputs are NIL or empty or contain a length word of zero, NIL is 
  365. returned, otherwise a new handle is created with the inputs placed end-
  366. to-end.
  367.  
  368. FUNCTION GSStringEqual(src1, src2: GSString255Hndl): BOOLEAN;
  369.      Asm #34
  370. Performs a case-insensitive comparison of two GS/OS Class 1 input 
  371. strings (length word + text).  If the strings are equal, TRUE is 
  372. returned.  NIL or empty handles are considered to have length of zero, 
  373. and two strings of length zero will be judged equal.
  374.  
  375. FUNCTION GSToZero(src: GSString255Hndl): Handle;  Asm #35
  376.  
  377. Converts a GS/OS Class 1 input string (length word + text) into a zero-
  378. terminated string.   Even if the input string is empty (NIL or empty 
  379. handle or length = 0) a zero handle will be created- an empty zero 
  380. handle has length 1 and contains only a zero terminator.
  381.  
  382. FUNCTION ZeroToGS(src: Handle): GSString255Hndl;  Asm #36
  383.  
  384. Converts a zero handle into a GS/OS Class 1 input string (length word + 
  385. text).  If the source handle is empty or has length zero, NIL is 
  386. returned, otherwise a new handle is created, the length word is set, 
  387. and the text is copied into it.
  388.  
  389. The next four calls are designed to assist XCMD's which use resources.  
  390. The IIGS Resource Manager prior to System 6.0 does not support "named" 
  391. resources, but there is a standard format for storing names of 
  392. resources in "name resources".  These callbacks provide a simple 
  393. library of routines to assist identifying resources by name.  See the 
  394. IIGS ToolBox Reference, vol. 3, for more information.
  395.  
  396. FUNCTION LoadNamedResource(whichType: ResType; name: Str255): Handle;
  397.      Asm #37
  398.  
  399. Searches for the resource of this type and name and loads it.  If the 
  400. resource is not found, returns NIL.  Respects the current resource 
  401. search path:  Starts from the current file, and only goes as deep as 
  402. the specified depth.
  403.  
  404. FUNCTION FindNamedResource(whichType: ResType; name: Str255; VAR 
  405. homeFile: INTEGER; VAR id: ResID): BOOLEAN;  Asm #38
  406.  
  407. Searches for the resource of this type and name. If the specified 
  408. resource is found, returns TRUE, and file and id are set to the 
  409. containing file and the resource ID.  If the resource is not found, 
  410. returns FALSE, and the file and ID are undefined.  Respects the current 
  411. resource search path:  Starts from the current file, and only goes as 
  412. deep as the specified depth.  Note:  It is important to take note of 
  413. the file number, because it would be possible to have two resources, in 
  414. different files, with the same ID, and different names:  If you asked 
  415. for the deeper of the two, and then attempted to load it by ID, you 
  416. would get the shallower one.
  417.  
  418. PROCEDURE SetResourceName(whichType: ResType; id: ResID; name: 
  419. Str255);  Asm #39
  420.  
  421. Changes the name of a given resource to "name".  Respects the current 
  422. resource search path:  Starts from the current file, and only goes as 
  423. deep as the specified depth.  If no resource can be found within the 
  424. search criteria, nothing will happen.  If you set a resource name to 
  425. the empty string, it has no name, and may then only be referred to by 
  426. type and ID.
  427.  
  428. The IIGS resource manager does not directly support named resources.  
  429. One effect of this is that you can delete resources, but the names 
  430. remain.  Therefore, when deleting a resource, named or not, it is a 
  431. good idea to call this routine and set the resource's name to the empty 
  432. string - thus clearing out the name.
  433.  
  434. This routine will not add a name unless there is a corresponding target 
  435. resource of the given type and ID.  If you are adding a new resource, 
  436. then, you must first add the resource, and then you may give it a name.
  437.  
  438. FUNCTION GetResourceName(whichType: ResType; id: ResID): Str255; Asm 
  439. #40
  440.  
  441. Returns the name of a given resource.  Respects the current resource 
  442. search path:  Starts from the current file, and only goes as deep as 
  443. the specified depth.  If the resource has no name, or if the resource 
  444. doesn't exist, you will get an empty string in both cases.  Thus, you 
  445. must use different means to determine the existence of the resource 
  446. itself.  This call only identifies the existence of a name - not the 
  447. resource itself.
  448.  
  449. The next two calls  are designed to assist XCMD's which wish to use the 
  450. IIGS sound hardware (referred to herein as the "DOC chip").  These 
  451. callbacks provide a very simple form of arbitrarion, by allowing the 
  452. XCMD's to reserve the DOC for their own use.  If you leave the XSound 
  453. activated, HyperCard IIGS will never be able to make another sound 
  454. (until re-launched) so if you must use these callbacks, PLEASE be sure 
  455. to call EndXSound at an appropriate time.  It is not automatic.
  456.  
  457. PROCEDURE BeginXSound;   Asm #41
  458.  
  459. Indicates to HyperCard IIGS that an XCMD would like to take over 
  460. control of the DOC chip.  After this call, HyperCard IIGS will never 
  461. emit sound from the speaker.  The play command will simply fall 
  462. through.  You MUST execute the EndXSound call for HyperCard IIGS to 
  463. make any more sounds.
  464.  
  465. PROCEDURE EndXSound;     Asm #42
  466.  
  467. Indicates to HyperCard IIGS that an XCMD has completed usage of the DOC 
  468. chip.  After this call is made,  HyperCard IIGS may resume its own use 
  469. of the DOC chip, and may begin making sounds.
  470.  
  471. The next two calls  are designed to assist XCMD's and which wish to do 
  472. image processing.  They provide an easy way to get images in and out of 
  473. HyperCard IIGS.  This could be used in conjunction with a scanner or 
  474. digitized XCMD, for example.  DO NOT use these calls during painting, 
  475. because there are a number of other buffers which are also involved.
  476.  
  477. PROCEDURE GetMaskAndData(VAR mask: LocInfo; VAR data: LocInfo);
  478.      Asm #43
  479.  
  480.  
  481. This call actually does two things:  first, HyperCard IIGS will update 
  482. its internal buffers to contain the up-to-date image;  second, it will 
  483. return the LocInfo records of the two image buffers.  The data buffer 
  484. is a card-sized buffer which contains the image of "the card".  The 
  485. mask buffer is a similar sized buffer which contains the "opaque" layer 
  486. of the card.  In the opaque layer, 0 = transparent and 1 = opaque.  
  487. Note:  ANY activities subsequent to this call can cause these buffers 
  488. to change, so an xcmd must finish using the buffers, or at least make 
  489. local copies, before making any of the callbacks which might update the 
  490. screen, change cards, etc.
  491.  
  492. PROCEDURE ChangedMaskAndData(whatChanged: INTEGER);    Asm #44
  493.  
  494. This callback is used by XCMDs which actually change the picture on a 
  495. card and wish it to be saved in the stack.  An XCMD which wants to 
  496. change a picture should contain the following sequence of operations:
  497.     GetMaskAndData;
  498.     MakeChanges;
  499.     ChangedMaskData(whatChanged);
  500.  
  501. The change codes are one of the following:
  502.  
  503. Code Meaning
  504. 0    No changes were made to the buffers, but please update the 
  505. screen.  This is a good way to update the card window if an XCMD has 
  506. been drawing in it.
  507. 1    The buffers were modified, but the XCMD does not wish to save the 
  508. changes.  Please restore them to their original state.
  509. 2    New data and mask have been placed in the buffers;  or, new data 
  510. was supplied and use the original mask.
  511. 3    New data was written, and this new image requires a mask buffer 
  512. of "all transparent".  HyperCard IIGS will fill the mask with zeros 
  513. before saving the pictures.
  514. 4    New data was written, and this new image requires a mask buffer 
  515. of "all opaque".  HyperCard IIGS will fill the mask with ones before 
  516. saving the pictures.
  517. 5    New data was written.  HyperCard IIGS will compute a new mask 
  518. buffer using the following algorithm:  all white data pixels become 
  519. transparent;  all non-white data pixels become opaque.
  520.  
  521. The callbacks listed below are new to HyperCard IIGS version 1.1.  
  522. Attempting to execute these callbacks with a version of HyperCard IIGS 
  523. prior to 1.1 will cause HyperCard to crash.  Care must be taken that 
  524. the correct version of HyperCard is in use before using these 
  525. callbacks.  Sample Pascal source is included below to illustrate a 
  526. means of checking the version from an XCMD.
  527.  
  528. FUNCTION CorrectVersion: BOOLEAN;
  529. { This returns true if the version of HyperCard is >= minVersion }
  530.      CONST
  531.           minVersion = '1.1';
  532.      VAR
  533.           tempHandle:    Handle;
  534.           tempStr:  Str255;
  535.      BEGIN
  536.           tempHandle := EvalExpr('the version');
  537.           ZeroToPas(tempHandle^, tempStr);
  538.           IF temphandle <> NIL THEN DisposeHandle(tempHandle);
  539.           CorrectVersion := tempStr >= minVersion;
  540.      END; {CorrectVersion}
  541.  
  542.  
  543. PROCEDURE PointToStr(pt: Point; VAR str: Str255); Asm #45
  544.  
  545. This callback converts a point to a Pascal string.  This is typically 
  546. used when an XCMD needs to return a point to HyperCard as an interim 
  547. measure before calling PasToZero to convert the new Pascal string to a 
  548. zero-terminated string.
  549.  
  550. PROCEDURE RectToStr(rct: Rect; VAR str: Str255);  Asm #46
  551.  
  552. Similar to PointToStr, this callback converts a rect to a Pascal 
  553. string.
  554.  
  555. PROCEDURE StrToPoint(str: Str255; VAR pt: Point); Asm #47
  556.  
  557. The compliment of PointToStr, this callback converts a Pascal string to 
  558. a point.  Missing coordinates will be converted to zero.  For example 
  559. the string "5,15" will be converted to a point with the horizontal 
  560. coordinate being five and the vertical coordinate being 15 while the 
  561. string "8" would result in a point with a horizontal coordinate of 
  562. eight and a vertical coordinate of zero.
  563.  
  564. PROCEDURE StrToRect(str: Str255; VAR pt: Point);  Asm #48
  565.  
  566. Similar to StrToPoint, this callback converts a string to a rect.
  567.  
  568. FUNCTION NewXWindow(boundsRect: Rect; title: Str31; 
  569.           visible: BOOLEAN; wStyle: INTEGER): WindowPtr;
  570.                     Asm #49
  571.  
  572. This callback creates an XWindow.  An XWindow is very similar to a 
  573. standard with several key exceptions noted below.  BoundsRect defines 
  574. the location and size of the content region of the window.  Note that 
  575. the actual size of the window frame depends upon the window style.  
  576. Title is a Pascal string of up to 31 characters which is used to 
  577. reference the window by name from HyperTalk.  The visible parameter 
  578. determines indicates whether the window will be created initially 
  579. visible.  WStyle is one of the following constants declared in the 
  580. HyperXCMD interface file.
  581.  
  582.      xWindoidStyle  0    Window has a grey drag bar and close box.
  583.      xRectStyle     1    A simple rectangle outlines the this style window.
  584.      xShadowStyle   2    A rectangle with a drop shadow on the bottom and right sides.
  585.      xDialogStyle   3    Identical in appearance to a dialog box.
  586.  
  587. As noted above, XWindows are very similar to standard windows obtained 
  588. via the NewWindow toolbox call.  The differences include:  (1)  The 
  589. programmer must never alter the wRefCon field of the window record.  
  590. Instead, use the SetXWindowValue callback if you wish to save a value 
  591. along with the window.  (2) The wFrameBits is inaccessible to the user 
  592. and must not be changed.  (3) The programmer should not call 
  593. CloseWindow on this window, instead, they must use the CloseXWindow 
  594. callback which will properly dispose of additional memory HyperCard has 
  595. allocated for the window and send the proper close event to the XCMD.
  596.  
  597. An XCMD that creates an XWindow has several additional 
  598. responsibilities.  These include responding to events specific to the 
  599. XWindow(s) it creates as well as disposing of any additional memory the 
  600. XCMD may have allocated when creating the XWindow.  See the section 
  601. "Care and Feeding of Your New XWindow" below for complete details on 
  602. responding to XWindow events.
  603.  
  604. PROCEDURE SetXWIdleTime(window: WindowPtr; interval: LongInt);
  605.                     Asm #50
  606.  
  607. This callback instructs HyperCard how often (in ticks) the XCMD would 
  608. like to receive null events for each XWindow it has created.  The 
  609. default is zero which indicates the XCMD does _not_ wish to receive 
  610. null events.  Care should be taken that an XWindow does not slow down 
  611. HyperCard unnecessarily by receiving more null events than it 
  612. absolutely requires.  A clock XWindow, for instance, would most likely 
  613. not need a null event more often than once per second at the most.
  614.  
  615. PROCEDURE CloseXWindow(window: WindowPtr);   Asm #51
  616.  
  617. This callback sends a closeEvent to the owner of the indicated XWindow, 
  618. releases all memory HyperCard has allocated for internal use regarding 
  619. the XWindow, and closes the window via a CloseWindow call.  
  620. Additionally, if the owner XCMD of the window being closed no longer 
  621. owns any windows, its code is disposed of and its memory ID released if 
  622. no calls are currently pending for it or marked for later disposal if 
  623. calls are currently pending.  The XCMD may save itself from being 
  624. disposed if it opens additional windows after it is marked for disposal 
  625. but still awaiting pending or recursive calls.
  626.  
  627. PROCEDURE HideHCPalettes;          Asm #52
  628.  
  629. This callback hides all currently open HyperCard windows including all 
  630. XWindows and all built-in windows except for the card window.  
  631. Additionally, it records the visible state of each window when the call 
  632. was executed so that a subsequent call to ShowHCPalettes can restore 
  633. all windows that were visible.  The xHidePalettesEvt XWindow message is 
  634. sent to every XWindow when this call is executed.  This callback is 
  635. typically used when it is necessary to clear the screen of 
  636. obstructions, such as when using the Apple II Video Overlay Card.
  637.  
  638. PROCEDURE ShowHCPalettes;          Asm #53
  639.  
  640. The compliment to HideHCPalettes, this callback shows all windows that 
  641. were visible at the time of the HideHCPalettes call and sends the 
  642. xShowPalettesEvt to every XWindow.
  643.  
  644. FUNCTION GetXWindowValue(window: WindowPtr): LongInt;  Asm #55
  645.  
  646. This callback retrieves the value of an XWindow previously set by the 
  647. SetXWindowValue callback below.  This value is inistailized to zero 
  648. when the XWindow is created.
  649.  
  650. PROCEDURE SetXWindowValue(window: WindowPtr; customValue:   
  651.      LongInt); Asm #54
  652.  
  653. This callback allows the XCMD owner of an XWindow to save a LongInt 
  654. (four byte) sized value along with an XWindow it creates.  Since an 
  655. XCMD may own multiple XWindows, this callback allows the XCMD to save a 
  656. unique value along with specific windows.  Typically, this value would 
  657. contain a picture handle for updates or a handle to a record containing 
  658. data needed for the particular XWindow.
  659.  
  660.  
  661. GETTING STARTED
  662.  
  663. It is strongly suggested that the XCMD author start by copying the 
  664. given sample XCMDs and modifying them.  The code itself is quite 
  665. simple, however the steps to build an XCMD are somewhat complex.  The 
  666. examples given are ABeep, PBeep and CBeep.  They each create a command 
  667. which simply beeps the speaker a given number of times.  Each version 
  668. comes in its own folder with a make file, program source, and a rez 
  669. source file.  These samples are included in MPW IIGS and APW format.
  670.  
  671. To make an XCMD, set the MPW directory to that folder, and select 
  672. Build.... from the build menu.  Type the XCMD name into the dialog, and 
  673. the build process should begin.  The final step in a successful build 
  674. is to copy the file containing the resource onto a ProDOS diskette.  
  675. Now you must use the supplied RMover utility.  This is a simple 
  676. resource mover with which you may add the new resource to an existing 
  677. stack file.  When you use Rmover, be sure to click the "Types" button 
  678. and select type $801E - XCMD, OMF.
  679.  
  680. After you place the XCMD in a stack, launch HyperCard IIGS and open the 
  681. stack containing the XCMD.  To invoke the XCMD, simply type it's name 
  682. and any required parameters into the message box.  From here on out, 
  683. it's welcome to the wonderful world of debugging.
  684.  
  685.  
  686.  
  687. To create a new XCMD, copy the entire folder and rename every 
  688. occurrence you can find of the resource name, to the new name.  That 
  689. is, rename every file, -and- open the text files and rename every 
  690. occurrence inside.
  691.  
  692.  
  693. NOT FOR THE FAINT OF HEART
  694.  
  695. If you really want to start messing around, I urge you to read and 
  696. completely understand the link commands and the rez source.  Many of 
  697. the high-level compilers especially like to create lots of segments, 
  698. and the makefile goes to great lengths to create a file which has (1) a 
  699. single segment and (2) an entry point at the 1st byte in the segment.
  700.  
  701.  
  702. CARE AND FEEDING OF YOUR NEW XWINDOW
  703. External commands that create XWindows are kept in memory after they 
  704. terminate so that they may be called in response to events concerning 
  705. the XWindows they created.  An XCMD can determine whether it has been 
  706. called from a script or the message box or in response to an event by 
  707. checking the paramCount field of the parameter block.  If this value is 
  708. negative, the XCMD has been called in response to an event.  The 
  709. following Pascal code fragment illustrates this concept.
  710.  
  711.      BEGIN {SampleXCMD}
  712.           { If the paramCount is negative, we have been called 
  713. in
  714.             response to an event }
  715.           IF paramPtr^.paramCount < 0 THEN BEGIN
  716.                HandleEvents;
  717.                EXIT(SampleXCMD);
  718.           END; {if}
  719.  
  720.           { program continues... }
  721.  
  722. The Events an External Command Will Receive
  723. Upon calling an XCMD in response to an event, the following conditions 
  724. are true:
  725.      
  726.      (1)  The current port is set to the XWindow which the 
  727. event deals with.
  728.      (2)  The memory ID field of the parameter block is the 
  729. same as when the
  730.           XCMD initially created the XWindow.
  731.      (3) The first parameter is a pointer to an XWEventInfoPtr
  732.  
  733. The structure of an XWEventInfoPtr is as follows:
  734.  
  735.      eventWindow: WindowPtr;
  736.      event:    EventRecord;
  737.      eventParams: ARRAY[1..9] OF LongInt;
  738.      eventResult: Handle;
  739.      
  740. The following is a list of all events an external command can receive 
  741. along with a description of the event.  Some of the events are standard 
  742. system events while others are generated by HyperCard.  In all cases 
  743. the event record consists of the following fields:
  744.  
  745.      what:          INTEGER;  { event code }
  746.      message:  Longint;  { event message }
  747.      when:     Longint;  { ticks since startup }
  748.      wher :    Point;    { mouse location }
  749.      modifiers:     INTEGER;  { modifier flags }
  750.  
  751.  
  752. HyperCard Event - "xOpenEvt"
  753. xOpenEvt is always the first event sent to any XWindow.  This event is 
  754. sent to any new XWindows immediately after the parent XCMD terminates.  
  755. No events will be sent to an XWindow before this event.
  756.  
  757. HyperCard Event - "xCloseEvt"
  758. This is HyperCard's method of notifying the XCMD that a window that it 
  759. created is being closed.  At the time of the event, the window is still 
  760. present and visible.  The window will be closed immediately following 
  761. the event.  The owner XCMD should not call CloseXWindow or close the 
  762. window in any other means when it receives this event.  HyperCard will 
  763. handle closing the window when the XCMD terminates.  XCMDs will 
  764. typically use this event to dispose of any additional memory they have 
  765. allocated for the XWindow.
  766.  
  767. HyperCard Event - "xHidePalettesEvt"
  768. This event is sent to all XWindows when an external command executes 
  769. the HideHCPalettes callback.  An external command may wish to 
  770. deallocate memory or take other action when the user hides their window 
  771. in this manner.
  772.  
  773. HyperCard Event - "xShowPalettesEvt"
  774. This event is sent to all XWindows when an external command executes 
  775. the ShowHCPalettes callback.  An external command may need to prepare 
  776. itself to handle update events, etc, if it has deallocated the memory 
  777. when being hidden.
  778.  
  779. HyperCard Event - "xCursorWithin"
  780. This event is sent to an XWindow when the mousecursor enters therect of 
  781. their window.  The owner XCMD can then set the cursor to a custom shape 
  782. if desired using the toolbox.  If they do not wish to handle the 
  783. changing of the cursor shape, the external command should set the 
  784. passFlag of the parameter block to TRUE so that HyperCard will handle 
  785. the cursor itself.  Since this message is sent repeatedly, as long as 
  786. the cursor is within the window, the XCMD should determine whether it 
  787. has already changed the cursor shape before doing so again to avoid 
  788. flickering of the cursor and slowing down the CPU. 
  789.  
  790. System Event - "UpdateEvt"
  791. This event indicates the all or part of the specified window needs to 
  792. be updated.  It is the responsibilty of the owner external of each 
  793. window to handle redrawing the contents of the window in response to 
  794. this event.
  795.  
  796. System Event - "MouseDownEvt"
  797. The user has pressed the mouse button while the mouse pointer was 
  798. within an external window.  The external command will commonly handle 
  799. tracking the mouse click manually, or call FindControl and have the 
  800. control manager do so.
  801.  
  802. System Event - "NullEvt"
  803. This event will only be sent if the XCMD/XFCN has enabled idle events 
  804. by setting the idle interval to a value other than zero with the 
  805. SetXWIdleTime callback.  See the description of this callback above for 
  806. more information regarding using null events.
  807.  
  808.  
  809. NOTES ABOUT XCMDS THAT OPEN XWINDOWS
  810. An XCMD that creates an XWindow is treated differently from an XCMD 
  811. that doesn't.  The following section details differences the XCMD 
  812. author needs to be aware of.
  813.  
  814. 1)  XCMDs that create external windows are kept in memory as long as 
  815. any XWindows that XCMD created are open.
  816. 2)  XWindow XCMDs should not assume that they own only one window.  
  817. Subsequent calls to the XCMD may create additional windows.  The XCMD 
  818. should use the windowPtr passed and the GetXWindowValue and 
  819. SetXWindowValue calls to determine the appropriate action to take in 
  820. response to a particular event.
  821. 3)  The same Memory Manager user ID is passed to an XWindow owner XCMD 
  822. as long as any of the XWindows the XCMD owns are open.  The XCMD should 
  823. not perform a DisposeAll on its memory ID because other windows that 
  824. the XCMD is responsible for are still open. 
  825. 4)  The wFrameBits field of an XWindow is inaccessible to an XCMD, 
  826. XCMDs should not attempt to modify the standard window attributes of an 
  827. XWindow.
  828. 5)  XWindows may remain open throughout various stacks.  Any resources 
  829. needed by a particular XWindow should be detached and maintained by the 
  830. XCMD when the window is opened.
  831. 6)  XCMDs that have currently open XWindows are inserted into the 
  832. heirarchy immediately after the stack script of the current stack.  
  833. XCMDs that open XWindows should be aware that they may be called from 
  834. HyperTalk after leaving their parent stack.
  835.